﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;

using System.Windows.Input;
using GalaSoft.MvvmLight.Command;
using MishraReader.Entities;
using MishraReader.Services;

#if !WINRT
using System.Threading.Tasks;
using MishraReader.ViewModels.AppServices;

#else
using Windows.System;
#endif

namespace MishraReader.ViewModels.Reader
{
    public interface IItemViewModel
    {
        IBookmarkViewModel BookmarkViewModel { get; }
        Item Item { get; }
        IShareViewModel ShareViewModel { get; }
        void NavigateTo(Item item);
    }

    public class ItemViewModel : TaskViewModelBase, IItemViewModel
    {
        private readonly IBookmarkViewModel _bookmarkViewModel;
        private readonly IUrlLauncher _launcher;
        private readonly IGoogleReaderService _gService;
        private readonly IOptionsManager _optionsManager;
        private readonly IShareViewModel _shareViewModel;
        private string _author;
        private bool _isApplyingReadState;
        private bool _isApplyingStarredState;
        private Item _item;
        private string _itemData;
        private PropertyObserver<Item> _itemObserver;
        private string _publicationDate;
        private bool _read;
        private bool _starred;
        private string _title;

        /// <summary>
        ///   Ctr
        /// </summary>
        public ItemViewModel(IOptionsManager optionsManager,
                             IGoogleReaderService gService,
                             IShareViewModel shareViewModel,
                             IBookmarkViewModel bookmarkViewModel,
                             IUrlLauncher launcher)
        {
            _optionsManager = optionsManager;
            _gService = gService;
            _shareViewModel = shareViewModel;
            _bookmarkViewModel = bookmarkViewModel;
            _launcher = launcher;
            ShareCommand = new RelayCommand(ExecuteShareCommand);
            ViewInBrowserCommand = new RelayCommand(ExecuteViewInBrowserCommand);
        }

        public string Author
        {
            get { return _author; }
            set
            {
                Set(ref _author, value);
            }
        }

        public ICommand BookmarkCommand { get; private set; }

        public IBookmarkViewModel BookmarkViewModel
        {
            get { return _bookmarkViewModel; }
        }

        /// <summary>
        /// </summary>
        public Item Item
        {
            get { return _item; }
            private set
            {
                if (_item != value)
                {
                    if (_itemObserver != null)
                    {
                        _itemObserver.UnregisterAllHandlers();
                        _itemObserver = null;
                    }

                    _item = value;

                    // Pass along to child VM's
                    _bookmarkViewModel.Item = value;
                    _shareViewModel.Item = value;

                    if (_item != null)
                    {
                        Read = !_item.Unread;
                        Starred = _item.Starred;

                        _itemObserver = PropertyObserver.Create(_item);
                        _itemObserver.RegisterHandler(i => i.Unread, _ => OnItemUnreadChanged());
                        _itemObserver.RegisterHandler(i => i.Starred, _ => OnItemStarredChanged());
                    }

                    RaisePropertyChanged();
                }
            }
        }

        public string ItemData
        {
            get { return _itemData; }
            private set
            {
                Set(ref _itemData, value);
            }
        }

        public string PublicationDate
        {
            get { return _publicationDate; }
            set
            {
                Set(ref _publicationDate, value);
            }
        }

        /// <summary>
        ///   Gets or sets a value indicating whether this <see cref="ItemViewModel" /> is read.
        /// </summary>
        /// <value> <c>true</c> if unread; otherwise, <c>false</c> . </value>
        public bool Read
        {
            get { return _read; }
            set
            {
                if (_read != value)
                {
                    _read = value;

                    // read state of the item is differents
                    if (_read == Item.Unread)
                        ApplyReadState();

                    RaisePropertyChanged();
                }
            }
        }

        public ICommand ShareCommand { get; private set; }


        public IShareViewModel ShareViewModel
        {
            get { return _shareViewModel; }
        }

        public bool Starred
        {
            get { return _starred; }
            set
            {
                if (_starred != value)
                {
                    _starred = value;

                    // read state of the item is differents
                    if (_starred != Item.Starred)
                        ApplyStarredState();

                    RaisePropertyChanged();
                }
            }
        }

        public string Title
        {
            get { return _title; }
            set
            {
                Set(ref _title, value);
            }
        }

        public ICommand ViewInBrowserCommand { get; private set; }

        public void NavigateTo(Item item)
        {
            Item = item;

            if (item == null)
            {
                Title = null;
                Author = null;
                PublicationDate = null;

                ItemData = null;

                return;
            }

            Title = item.Title;

            // This happens, buy why? Is it when you have an item starred but no subscription to the feed?
            Author = item.Subscription != null ? item.Subscription.Title.ToUpper() : null;

            PublicationDate = item.FormatedPublicationDate;

            ItemData = GetItemContentOrUri(item);
        }


        /// <summary>
        ///   Mark or unmark item as Read according to the associated item
        /// </summary>
        private void ApplyReadState()
        {
            _isApplyingReadState = true;

            if (Read)
                _gService.MarkAsReadAsync(Item);
            else
                _gService.MarkAsUnreadAsync(Item);

            _isApplyingReadState = false;
        }


        private void ApplyStarredState()
        {
            _isApplyingStarredState = true;

            if (Starred)
                _gService.MarkAsStarredAsync(Item);
            else
                _gService.MarkAsUnstarredAsync(Item);

            _isApplyingStarredState = false;
        }

        /// <summary>
        ///   Execute share command
        /// </summary>
        private void ExecuteShareCommand()
        {
            // TODO: Refactor so VM doesn't create a view
            //var view = _shareViewFactory();
            //view.DataContext = ShareViewModel;
            //view.ShowDialog();

            ShareViewModel.ShowDialog();
        }

        private void ExecuteViewInBrowserCommand()
        {
            _launcher.LaunchUri(Item.PostUri);
        }

        private static string _htmlContentHeader;
        private static string _htmlContentFooter;

        private String GetHtml(string data)
        {
            if (_htmlContentHeader == null)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
                sb.AppendLine("<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
                sb.AppendLine(
                    @"<style>
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
    font-family:Segoe UI;
	vertical-align: baseline;
    color:#333333;
}

/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
	display: block;
}
body {
    background-color:#ffffff;
}
li
{
   margin:5px 15px;
}
ol, ul {
	list-style-type:disc;
    margin:0px 15px;
}
h1, h2, h3{ margin:20px 0px;}
blockquote, q {
	quotes: none;
    margin:5px 10px;
    font-style:italic;
}
p
{
    margin:15px 0px;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}
table {
	border-collapse: collapse;
	border-spacing: 0;
}");

 sb.AppendFormat(@"html
{{	
    scrollbar-base-color: #5D5D5D;
    scrollbar-arrow-color: white;
    scrollbar-track-color:  white;

    scrollbar-shadow-color: white;
    scrollbar-lightshadow-color: white; 
    scrollbar-darkshadow-color: white;

    scrollbar-highlight-color: white;
    scrollbar-3dlight-color: white;
}}
a{{border:0px;color:{0}}}
a img {{border: 0px;}}
</style>", _optionsManager.AccentColorCode);
                sb.AppendLine("</head><body>");

                _htmlContentHeader = sb.ToString();
            }

            if (_htmlContentFooter == null)
            {
                _htmlContentFooter = "</body></html>";   
            }

            return String.Concat(_htmlContentHeader, data, _htmlContentFooter);
            
        }
        private string GetItemContentOrUri(Item item)
        {
            string data;
            try
            {
                data = item.Content != null
                           ? item.Content.Data
                           : (item.Summary != null ? item.Summary.Data : Strings.NoContentFound);

                if (_optionsManager.ShowOnlyPostSummary)
                {
                    data = GetHtml(data);
                }
                else
                {
                    data = item.PostUri.ToString();
                }
            }
            catch (Exception ex)
            {
                data = GetHtml(String.Format("{0}<br>{1}", Strings.ErrorDuringParsing, ex.Message));
            }

            return data;
        }

        private void OnItemStarredChanged()
        {
            if (_isApplyingStarredState)
                return;

            Starred = Item.Starred;
            ApplyStarredState();
        }

        private void OnItemUnreadChanged()
        {
            if (_isApplyingReadState)
                return;

            Read = !Item.Unread;
            ApplyReadState();
        }
    }
}